/**
 * Independent time operation tool to facilitate subsequent switch to dayjs
 */
import dayjs from 'dayjs';
import type { Dayjs } from 'dayjs';
import { isNumber } from './is';
import weekOfYearPlugin from 'dayjs/plugin/weekOfYear';

const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
const DATE_MINUTE_FORMAT = 'YYYY-MM-DD HH:mm';
const DATE_FORMAT = 'YYYY-MM-DD';
const DATE_MONTH = 'YYYY-MM';
const DATE_YEAR = 'YYYY';

export function formatToDateTime(
  date: dayjs.Dayjs | undefined = undefined,
  format = DATE_TIME_FORMAT,
): string {
  return dayjs(date).format(format);
}

export function formatToDate(
  date: dayjs.Dayjs | undefined = undefined,
  format = DATE_FORMAT,
): string {
  return dayjs(date).format(format);
}

/**
 * 获取当前时间戳,单位秒
 */
export const getTimestamp = ()=>{
  return dayjs().unix();
};

export const dateUtil = dayjs;

/**
 * @description: 日期时间格式转换
 */
export const timestampToTime = (timestamp:number):string =>{
  if(timestamp && timestamp>0){
    return dayjs.unix(timestamp).format(DATE_TIME_FORMAT);
  }
  return '';
};
/**
 * @description: 日期时间格式转换 精确到分钟
 */
export const timestampToMinute = (timestamp:number):string =>{
  if(timestamp && timestamp>0){
    return dayjs.unix(timestamp).format(DATE_MINUTE_FORMAT);
  }
  return '';
};

/**
 * @description: 日期格式转换
 */
export const timestampToDate = (timestamp:number):string =>{
  if(timestamp && timestamp>0){
    return dayjs.unix(timestamp).format(DATE_FORMAT);
  }
  return '';
};

/**
 * @description: 月份格式转换
 */
 export const timestampToMonth = (timestamp:number):string =>{
  if(timestamp && timestamp>0){
    return dayjs.unix(timestamp).format(DATE_MONTH);
  }
  return '';
};

/**
 * @description: 年份格式转换
 */
 export const timestampToYear = (timestamp:number):string =>{
  if(timestamp && timestamp>0){
    return dayjs.unix(timestamp).format(DATE_YEAR);
  }
  return '';
};

/**
 * @description: 禁止选择小于当前的日期
 */
export const disabledDate = (current: Dayjs) => {
  // Can not select days before today and today
  return current && current < dayjs().endOf('day');
};

/**
 * 传入总秒数，返回时间字符串
 * @param _sec 时间秒数
 * @param maxUnit 最多显示单位,[天,小时,分,秒],从左开始,第一个值大于0的计算
 */
export const getSecToDHMS = (_sec: number, maxUnit = 4) => {
  let day = 0, hour = 0, minute = 0, second = 0;

  let sec:number = _sec;// 总秒数
  if (sec >= 86400) {
    day = parseInt((sec / 86400) as any);
    sec = sec % 86400;
  }
  if (sec >= 3600) {
    hour = parseInt((sec / 3600) as any);
    sec = sec % 3600;
  }
  if (sec >= 60) {
    minute = parseInt((sec / 60) as any);
    sec = sec % 60;
  }
  if (sec > 0) {
    second = sec;
  }

  const valueArray = [
    { t:'天',v: day },
    { t:'小时',v: hour },
    { t:'分',v: minute },
    { t:'秒',v: second },
  ];

  const defaultUnit = 3;
  const valueUnit = (maxUnit <= 0 || maxUnit > valueArray.length) ? defaultUnit : maxUnit;
  const beginIndex = valueArray.findIndex(item => item.v > 0);
  const endIndex = beginIndex + valueUnit;

  let arr = [];
  if (endIndex < valueArray.length) {
    arr = valueArray.slice(beginIndex, endIndex);
  } else {
    arr = valueArray.slice(beginIndex);
  }
  return  arr.map((item,index)=>{
    const { t,v } = item;
    //如果值为0且为最后一个
    if(v===0 && index===arr.length-1){
     return '';
    }
    return `${v}${t}`;
  }).join('');
};

/**
 * @description: 显示时间的格式
 * @param { string } time 时间 如：'00:00' 或 '00:00:00'
 * @param { string } format 格式 如：'HH:mm' 或 'HH:mm:ss'
 * @return { object } 转换后的时间格式
 */
export const setShowTime = (time:string, format:string): object => {
  return { defaultValue: dayjs(time, format) };
};

/**
 * @description: 预设常用的日期范围
 */
export const ranges:any = {
  '今天': [dayjs().startOf('day'), dayjs().endOf('day')],
  '本周': [dayjs().startOf('week'), dayjs().endOf('week')],
  '上一周': [dayjs().add(-1, 'week').startOf('week').add(0, 'day'), dayjs().add(-1, 'week').endOf('week').add(0, 'day')],
  '本月': [dayjs().startOf('month'), dayjs().endOf('month')],
  '近30天': [dayjs(), dayjs().add(30, 'day').endOf('day')],
  '本年': [dayjs().startOf('year'), dayjs().endOf('year')],

  '过去24小时': [dayjs().add(-24,'hour'), dayjs()],
  '过去3天': [dayjs().add(-3,'day'), dayjs()],
  '过去7天': [dayjs().add(-7,'day'), dayjs()],
  '过去30天': [dayjs().add(-30,'day'), dayjs()],
  '过去90天': [dayjs().add(-90,'day'), dayjs()],
  '过去1年': [dayjs().add(-1,'year'), dayjs()],
};

/**
 * @description: 预设常用的日期范围
 * @param { Array } arr 预设的范围字段 如：['今天','本月','过去7天','过去30天','过去90天']
 * @return { object } 对应需要显示的预设日期范围字段；
 */
export const getRanges = (arr:Range[]): any[] =>{
  if (!arr.length) return [];
  const reRanges = arr.map((key:string) => ({ label: key, value: ranges[key] })); 
  return reRanges;
};

//常用日期范围选择
export type Range = '今天'|'本周'|'上一周'|'本月'|'本年'|'近30天'|'过去24小时'|'过去3天'|'过去7天'|'过去30天'|'过去90天'|'过去1年';

/**
 * @description: 获取计算日期之间的相差值
 * @param { string } startDate 需要计算的开始日期
 * @param { string } endDate 需要计算的结束日期
 */
export const getCalculateDateDiff = (startDate: string, endDate: string) => {
  if(!startDate || !endDate) return { year: 0, month: 0, day: 0 };
  
  const sDate: any = new Date(startDate); // 转换时间格式
  const sYear = sDate.getFullYear(); // 取当年的年
  const sMonth = sDate.getMonth() + 1; // 取当年的月(月份加一)
  const sDay = sDate.getDate(); // 取当年的日期
  const eDate: any = new Date(endDate); // 转换时间格式
  const eYear = eDate.getFullYear(); // 取现在的年
  const eMonth = eDate.getMonth() + 1; // 取现在的月(月份加一)
  const eDay = eDate.getDate(); // 取现在的日期
  /**
   * 日期计算(结束 - 开始)
   * 1-1当差值为正，就相差多少天
   */
  const restDday = Math.ceil((eDate - sDate) / (1000 * 60 * 60 * 24));
  /**
   * 月份计算(结束 - 开始)
   * 1-1当差值为正，就相差多少月
   * 1-1-1例如: (2021/3/15 - 2022/4/18) ===== 4-3 > 0 月份相差1月
   * 1-2当差值为负，计算从开始时间的月份到结束时间的月份相差几天
   * 1-2-1例如：(2021/5/15 - 2022/4/10) ===== 4-5 < 0
   * 其实就是计算从5月到第二年4月过了多少月
   * 1-2-1-1：方法： 向年借一年为12月计算过了多少月
   */
  const restMonth = eMonth - sMonth < 0 ? 12 + eMonth - sMonth : eMonth - sMonth;
  /**
   * 年份计算(结束 - 开始)
   * 直接限制结束比开始大，只有0/正数
   */
  const restYear = eYear - sYear;
  /**
   * 计算借位的问题
   */
  let resultMonth = restMonth, resultYear = restYear;
  // 日期小说明借了月
  if (eDay < sDay) {
    resultMonth = restMonth - 1 < 0 ? restMonth - 1 + 12 : restMonth - 1;
  }
  // 月份小借了年 或者 日期小，月份刚好一致，因为日期借了月份，导致月份减1，所以减年
  if (eMonth < sMonth || (eDay < sDay && eDay === sDay)) {
    resultYear = restYear - 1;
  }
  return { year: resultYear, month: resultMonth, day: restDday };
};
/**
 * 判断每年的每个月的最后一天是几号
 * @param mo-月份
 * @param year-年份
 * @returns {number}
 */
export const lastDay = (mo: number, year: number) => {
  if (mo === 4 || mo === 6 || mo === 9 || mo === 11) {
    return 30;
  }
  else if (mo === 2) { //2月
    if (isLeapYear(year)) { return 29; } 
    else { return 28; }
  }else { //大月
    return 31;
  }
};

/**
 * 增加月份
 * @beginDateStr 延期开始时间（格式：YYYY-MM-DD）
 * @delayNum 延期月份
 * @returns {str} 延期后时间
 */
export const dateAddMonth = (beginDateStr: string, delayNum: number) => {
  // 正常月份延期
  const delayDate = dayjs(beginDateStr).add(delayNum, 'month').format('YYYY-MM-DD');
  const dateArr = beginDateStr.split('-');
  const lastDayMonth = lastDay(Number(dateArr[1]), Number(dateArr[0]));
  if (Number(dateArr[2]) == lastDayMonth) { // 判断是否是当月最后一天
    const delayDateArr = delayDate.split('-');
    const lastDayMonth = lastDay(Number(delayDateArr[1]), Number(delayDateArr[0]));
    return delayDateArr[0] + '-' + delayDateArr[1] + '-' + lastDayMonth;
  }
  return delayDate;
};

/**
 * 判断是否是闰年
 * @param Year-年份
 * @returns {boolean}
 */
export const isLeapYear = (Year:number): boolean => {
  return (Year % 4 === 0 && Year % 100 !== 0) || Year % 400 === 0;
};

/**
 * 将数字时长转换为字符串时长格式 如：800 转 (HH:mm)[08:00]
 * @param value-数字时间
 * @returns {string}
 */
export const replaceHours = (value:number): string => {
  if(isNumber(value)){
    if(value === 0) return '00:00';
    const tLength = (value.toString()).length;
    const t_minute = (value.toString()).slice((tLength - 2), tLength);
    const t_hour = (value.toString()).slice(0, (tLength - 2));
    return (Number(t_hour) < 10 ? '0' + t_hour : t_hour) + ':' + t_minute;
  }
  return value || '';
};

/**
 * 将字符串时长转换为数字格式 如：(HH:mm)[08:00] 转 800
 * @param value-数字时间
 * @returns {string}
 */
export const hourChangeDigit = (value:string): number => {
  if(!value) return 0;
  const num = parseInt(value.replace(/:/g, ''));
  return num;
};

/**
 * 将时间转数字时间戳 如： 360转 (HH:mm)[06:00] 
 * @param value-数字时间
 * @returns {string}
 */
export const timeStampTurnTimeStr = (value:number): string => {
  if(!value || value <= 0 ) return '00:00';
  const hours = parseInt((value / 60) as any);
  
  if(hours >= 24) return '00:00';

  const minutes = value - hours * 60;
  return (hours < 10 ? ('0' + hours) : hours) +':'+ (minutes < 10 ? ('0' + minutes) : minutes);
};

/**
 * 将时间转数字时间戳 如：(HH:mm)[06:00] 转 360
 * @param value-数字时间
 * @returns {number}
 */
export const timeStrTurnTimeStamp = (value:string): number => {
  if(!value || !value.length) return 0;
  const timeArray = value.split(':');
  const hour = Number(value[0]) * 60;
  const minute = timeArray[1];
  return Number(hour) + Number(minute);
};

//插件
export const setupPlugin = ()=>{
  dayjs.extend(weekOfYearPlugin);
};

/**
 * 判断指定时间戳和当前时间相差天数是否在指定天数内
 * @param timestamp 时间戳
 * @param days 天数
 */
export const inDiffDays = (timestamp: number, days: number) => {
  if (!timestamp || timestamp <= 0) {
    return false;
  }
  const value = dayjs.unix(timestamp).diff(dayjs(), 'days');
  return Math.abs(value) <= days;
};

export default dayjs;

/**
 * 分钟数转换时间
 * @param minutes 分钟数
 */
export const minutesFormat = (minutes:number)=>{
  if(!minutes || minutes <=0){
    return '00:00';
  }
  const hour = Math.floor(minutes/60) %24;
  const minute = Math.floor(minutes%60);
  const hour_text = hour<10?`0${hour}`:`${hour}`;
  const minute_text = minute<10?`0${minute}`:`${minute}`;
  return `${hour_text}:${minute_text}`;
};

/**
 * 根据传入的日期时间格式, 支持格式如下：
 * /yyyy-MM-dd
 * //yyyy-MM-dd HH:mm
 * //yyyy-MM-dd HH:mm:ss
 * //对比两个时间,返回秒差,开始时间不传和异常返回-1,结束时间不传为当前时间
 * @param bDateStr 开始日期时间
 * @param eDateStr 结束日期时间
 */
export const compareDateReSec = (bDateStr:any, eDateStr?: any) => {
  if(!bDateStr || bDateStr == "null"){
		return -1;
	}
  try{
		let bDate = new Date(bDateStr.replace(/-/g,"/"));
    let eDate = null;
		if(!eDateStr || eDateStr == "null"){
			eDate = new Date();
		}else{
			eDate = new Date(eDateStr.replace(/-/g,"/"));
		}
		let s= (eDate.getTime()/1000)-(bDate.getTime()/1000);
		if(isNaN(s)){
			return -1;	
		}
		return s;
	}catch(e){
		return -1;
	}
};